﻿@using Microsoft.AspNetCore.Components;
@using System.Xml;
@using System.Reflection;
<div id="@Id">
    @if (Parameters.Any())
    {
        <h3 style="font-weight: 700;font-size: 20px;line-height: 28px;margin: 48px 0 8px;display: flex;align-items: center;">@Title 的参数</h3>
        <TTable TItem="Parameter" Data="Parameters" >
            <TTableFieldColumn Field="f=>f.Name" Header="名称" style="width:200px"></TTableFieldColumn>
            <TTableFieldColumn Field="f=>f.Type" Header="类型">
                <code>@context?.Type</code>
            </TTableFieldColumn>

            <TTableFieldColumn Field="f=>f.Description" Header="描述"></TTableFieldColumn>
            <TTableFieldColumn Field="f=>f.Default" Header="默认值" style="width:100px"></TTableFieldColumn>
            <TTableFieldColumn Field="f=>f.Required" Header="必填" style="width:80px">
                @if (context.Required)
                {
                    <TTag Theme="Theme.Danger">Y</TTag>
                }
                else
                {
                    <TTag Type="TagType.Outline" Theme="Theme.Success">N</TTag>
                }
            </TTableFieldColumn>

        </TTable>
    }
    @if (Methods.Any())
    {

        <h3 style="font-weight: 700;font-size: 20px;line-height: 28px;margin: 48px 0 8px;display: flex;align-items: center;">@Title 的方法</h3>
        <TTable TItem="Method" Data="Methods">
            <TTableFieldColumn Field="f=>f.Name" Header="名称" style="width:200px"></TTableFieldColumn>
            <TTableFieldColumn Field="f=>f.Parameter" Header="参数" style="width:200px"></TTableFieldColumn>
            <TTableFieldColumn Field="f=>f.Description" Header="描述"></TTableFieldColumn>
        </TTable>
    }
</div>
@code {
    /// <summary>
    /// 标题
    /// </summary>
    [Parameter] public string? Title { get; set; } 
    /// <summary>
    /// 参数
    /// </summary>
    List<Parameter>? Parameters { get; set; }
    /// <summary>
    /// 方法
    /// </summary>
    List<Method>? Methods { get; set; }
    /// <summary>
    /// 组件类型
    /// </summary>
    [Parameter] public Type? Component { get; set; }
    [Parameter] public string? Id { get; set; }

    [Inject] HttpClient? _client { get; set; }
    [Inject] IJSRuntime JS { get; set; }
    bool IsWasm => JS is IJSInProcessRuntime;
    protected override async Task OnParametersSetAsync()
    {
        Title ??= TypeToCSharp(Component);
        await InitApiAsync();
    }
    private async Task InitApiAsync()
    {
        var bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
        var propertys = Component?.GetProperties(bindingFlags);
        var methods = Component?.GetMethods(bindingFlags).Where(x => !x.IsVirtual && !x.IsSpecialName);
        Parameters = new List<Parameter>();
        Methods = new List<Method>();

        foreach (var itme in propertys)
        {
            var editorRequiredAttributes = itme.GetCustomAttributes(typeof(EditorRequiredAttribute), true);
            var type = TypeToCSharp(itme.PropertyType);
            var @default = itme.PropertyType.IsGenericType || !itme.PropertyType.IsValueType ? "null" : Activator.CreateInstance(itme?.PropertyType)?.ToString();
            Parameter parameter = new()
                {
                    Name = itme.Name,
                    Default = @default,
                    Description = $"{await GetXmlDescription($"P:{itme?.DeclaringType?.FullName}.{itme?.Name}")}{await GetEnumFildJoin(itme?.PropertyType)}",
                    Required = editorRequiredAttributes.Any(),
                    Type = type
                };
            Parameters.Add(parameter);

        }

        foreach (var itme in methods)
        {
            var key = $"M:{itme?.DeclaringType?.FullName}.{itme?.Name}({String.Join(",", itme.GetParameters().Select(x => x.ParameterType.FullName))})";
            Method method = new()
                {
                    Name = $"{itme.Name}",
                    Description = await GetXmlDescription(key),
                    Parameter = String.Join(", ", itme.GetParameters().Select(x => $"{x.ParameterType.Name} {x.Name}"))
                };
            Methods.Add(method);
        }
    }

    /// <summary>
    /// 获取xml文件代码注释
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    private async Task<string?> GetXmlDescription(string key)
    {

        XmlDocument xml = new XmlDocument();

        if (IsWasm)
        {
            // WebAssembly
            var xmlStream = await _client.GetStreamAsync("TDesign.xml");
            xml.Load(xmlStream);
        }
        else
        {
            // Server
            var xmlPath = System.IO.Path.Combine(".", "TDesign.xml");
            xml.Load(xmlPath);
        }

        var members = xml.SelectNodes("/doc/members/member");

        foreach (XmlNode item in members)
        {
            if (item?.Attributes["name"]?.Value == key)
            {
                return item?.ChildNodes[0]?.InnerText?.Replace(" ", "").Replace("\n", "").Replace("\r", "");
            }
        }
        return "";
    }

    /// <summary>
    /// TypeIL转C#代码风格
    /// </summary>
    /// <param name="types"></param>
    /// <returns></returns>
    private string? TypeToCSharp(params Type[] types)
    {
        var reuslt = "";
        for (int i = 0; i < types.Length; i++)
        {
            var item = types[i];
            var comma = i == types.Length - 1 ? "" : ",";
            if (item.IsGenericType)
            {
                reuslt += $"{item.Name.Split("`")[0]}<{TypeToCSharp(item.GenericTypeArguments)}{comma}>";
            }
            else
            {
                var enumLable = "";
                if (item.IsEnum) { enumLable = "enum:"; }
                reuslt += $"{enumLable}{item.Name}{comma}";
            }
        }
        return reuslt;
    }

    /// <summary>
    /// 枚举字段注释
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private async Task<string?> GetEnumFildJoin(Type type)
    {
        var reuslt = "";
        if (type.IsEnum)
        {
            var fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.Static);
            foreach (var item in fieldInfos)
            {
                reuslt += await GetXmlDescription($"F:{item?.DeclaringType?.FullName}.{item?.Name}") + "\n";
            }
        }
        return reuslt;
    }

    /// <summary>
    /// 参数列表模型
    /// </summary>
    public class Parameter
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string? Name { get; set; }
        /// <summary>
        /// 类型
        /// </summary>
        public string? Type { get; set; }
        /// <summary>
        /// 默认值
        /// </summary>
        public string? Default { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public string? Description { get; set; }
        /// <summary>
        /// 必填
        /// </summary>
        public bool Required { get; set; }
    }

    /// <summary>
    /// 方法列表模型
    /// </summary>
    public class Method
    {

        /// <summary>
        /// 名称
        /// </summary>
        public string? Name { get; set; }
        /// <summary>
        /// 参数
        /// </summary>
        public string? Parameter { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public string? Description { get; set; }
    }
}
